package com.har01d.tool;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.Signature;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.Base64;

final class JetBrainsUtil {

    private static final Logger log = LoggerFactory.getLogger(JetBrainsUtil.class);

    private static final String SIGN_TEMPLATE = "<!-- %s -->\n";

    private static final String OBTAIN_TICKET_TEMPLATE =
            "<ObtainTicketResponse>\n" +
                    "    <message></message>\n" +
                    "    <prolongationPeriod>607875500</prolongationPeriod>\n" +
                    "    <responseCode>OK</responseCode>\n" +
                    "    <salt>%s</salt>\n" +
                    "    <ticketId>1</ticketId>\n" +
                    "    <ticketProperties>licensee=%s\tlicenseType=0\t</ticketProperties>\n" +
                    "</ObtainTicketResponse>";

    private static final String RELEASE_TICKET_TEMPLATE =
            "<ReleaseTicketResponse>\n" +
                    "    <message></message>\n" +
                    "    <responseCode>OK</responseCode>\n" +
                    "    <salt>%s</salt>\n" +
                    "</ReleaseTicketResponse>";

    private static final String PROLONG_TICKET_TEMPLATE =
            "<ProlongTicketResponse>\n" +
                    "    <message></message>\n" +
                    "    <responseCode>OK</responseCode>\n" +
                    "    <salt>%s</salt>\n" +
                    "    <ticketId>1</ticketId>\n" +
                    "</ProlongTicketResponse>";

    private static final String PING_TEMPLATE =
            "<PingResponse>\n" +
                    "    <message></message>\n" +
                    "    <responseCode>OK</responseCode>\n" +
                    "    <salt>%s</salt>\n" +
                    "</PingResponse>";

    private static final String JETBRAINS_PRIVATE_KEY =
            "MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAt5yrcHAAjhglnCEn" +
                    "6yecMWPeUXcMyo0+itXrLlkpcKIIyqPw546bGThhlb1ppX1ySX/OUA4jSakHekNP" +
                    "5eWPawIDAQABAkBbr9pUPTmpuxkcy9m5LYBrkWk02PQEOV/fyE62SEPPP+GRhv4Q" +
                    "Fgsu+V2GCwPQ69E3LzKHPsSNpSosIHSO4g3hAiEA54JCn41fF8GZ90b9L5dtFQB2" +
                    "/yIcGX4Xo7bCvl8DaPMCIQDLCUN8YiXppydqQ+uYkTQgvyq+47cW2wcGumRS46dd" +
                    "qQIhAKp2v5e8AMj9ROFO5B6m4SsVrIkwFICw17c0WzDRxTEBAiAYDmftk990GLcF" +
                    "0zhV4lZvztasuWRXE+p4NJtwasLIyQIgVKzknJe8VOt5a3shCMOyysoNEg+YAt02" +
                    "O98RPCU0nJg=";


    static String obtainTicket(String salt, String userName) {
        String data = String.format(OBTAIN_TICKET_TEMPLATE, salt, userName);
        return signData(data);
    }

    static String releaseTicket(String salt) {
        String data = String.format(RELEASE_TICKET_TEMPLATE, salt);
        return signData(data);
    }

    static String prolongTicket(String salt) {
        String data = String.format(PROLONG_TICKET_TEMPLATE, salt);
        return signData(data);
    }

    static String ping(String salt) {
        String data = String.format(PING_TEMPLATE, salt);
        return signData(data);
    }

    private static String signData(String data) {
        String sign = String.format(SIGN_TEMPLATE, sign(data));
        return sign + data;
    }

    private static String sign(String data) {
        try {
            PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(Base64.getDecoder().decode(JETBRAINS_PRIVATE_KEY.getBytes()));
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            PrivateKey privateK = keyFactory.generatePrivate(pkcs8KeySpec);
            Signature signature = Signature.getInstance("MD5withRSA");
            signature.initSign(privateK);
            signature.update(data.getBytes());
            byte[] bytes = signature.sign();
            StringBuilder sb = new StringBuilder();
            for (byte b : bytes) {
                int v = b & 0xFF;
                String hv = Integer.toHexString(v);
                if (hv.length() < 2) {
                    sb.append(0);
                }
                sb.append(hv);
            }
            return sb.toString();
        } catch (Exception e) {
            log.warn(e.getMessage(), e);
            return null;
        }
    }

}
